#include "database/mysql_helper.h"
#include "LoggerManager.h"
#include <cppconn/exception.h>
#include <sstream>

namespace cpp_backend
{
    namespace database
    {

        using namespace logger;

        // ============================================================================
        // MySQLHelper实现 - 数据库操作助手类
        // ============================================================================

        /**
         * @brief 执行普通SQL查询（不带参数）
         *
         * ⚠️ 安全警告：此方法直接执行SQL字符串，存在SQL注入风险！
         *
         * 什么是SQL注入？
         * --------------
         * SQL注入是一种常见的网络攻击方式。攻击者通过在输入中插入恶意SQL代码，
         * 改变原SQL语句的逻辑，从而获取、修改或删除数据库数据。
         *
         * 例如：
         * string username = "admin' OR '1'='1";
         * string sql = "SELECT * FROM users WHERE username='" + username + "'";
         * // 实际执行：SELECT * FROM users WHERE username='admin' OR '1'='1'
         * // '1'='1'永远为真，导致返回所有用户数据！
         *
         * 建议：
         * - 仅用于执行固定的、不包含用户输入的SQL语句
         * - 如果SQL中包含用户输入，请使用QueryWithParams()方法
         *
         * @param sql SQL查询语句（不应包含用户输入）
         * @return JSON数组，包含查询结果
         */
        nlohmann::json MySQLHelper::Query(const std::string &sql)
        {
            try
            {
                MySQLConnectionGuard guard;
                if (!guard.IsValid())
                {
                    LOG_ERROR << "Failed to get MySQL connection";
                    return nlohmann::json::array();
                }

                sql::Statement *stmt = guard->createStatement();
                sql::ResultSet *res = stmt->executeQuery(sql);

                nlohmann::json result = ResultSetToJson(res);

                delete res;
                delete stmt;

                return result;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "MySQL query exception: " << e.what();
                LOG_ERROR << "  SQL: " << sql;
                return nlohmann::json::array();
            }
        }

        /**
         * @brief 执行带参数的SQL查询（推荐使用，防止SQL注入）
         *
         * ✅ 推荐方法：使用PreparedStatement（预处理语句）
         *
         * 什么是预处理语句（PreparedStatement）？
         * ---------------------------------------
         * 预处理语句是一种安全的SQL执行方式，它将SQL语句和参数分开处理：
         *
         * 1. SQL语句模板：使用?作为占位符
         *    例如："SELECT * FROM users WHERE username = ? AND password = ?"
         *
         * 2. 参数绑定：单独传递参数值
         *    例如：params[0] = "admin", params[1] = "123456"
         *
         * 3. 执行过程：
         *    - 数据库先编译SQL模板（确定语句结构）
         *    - 然后将参数作为纯数据值填入
         *    - 参数中的特殊字符会被自动转义，不会被当作SQL代码执行
         *
         * 为什么能防止SQL注入？
         * -------------------
         * 因为参数值被当作纯数据处理，不会被解释为SQL代码：
         * - 即使用户输入 "admin' OR '1'='1"，也只会被当作一个字符串值查找
         * - 不会改变SQL语句的结构和逻辑
         *
         * 例子对比：
         * ----------
         * ❌ 不安全（拼接字符串）：
         *    string sql = "SELECT * FROM users WHERE username='" + username + "'";
         *    // username="admin' OR '1'='1" 会导致SQL注入
         *
         * ✅ 安全（预处理语句）：
         *    string sql = "SELECT * FROM users WHERE username = ?";
         *    params = {"admin' OR '1'='1"};
         *    // 会被当作普通字符串，查找用户名为"admin' OR '1'='1"的用户
         *
         * @param sql SQL查询语句模板（使用?作为占位符）
         * @param params 参数列表（按顺序替换SQL中的?）
         * @return JSON数组，包含查询结果
         */
        nlohmann::json MySQLHelper::QueryWithParams(const std::string &sql,
                                                    const std::vector<std::string> &params)
        {
            try
            {
                MySQLConnectionGuard guard;
                if (!guard.IsValid())
                {
                    LOG_ERROR << "Failed to get MySQL connection";
                    return nlohmann::json::array();
                }

                // 创建预处理语句对象
                // PreparedStatement会将SQL语句和参数分开处理，防止SQL注入
                sql::PreparedStatement *pstmt = guard->prepareStatement(sql);

                // 绑定参数（索引从1开始，不是0！）
                // 每个参数会被安全地替换到SQL中的?占位符位置
                // setString()会自动转义特殊字符，确保参数作为纯数据处理
                for (size_t i = 0; i < params.size(); ++i)
                {
                    pstmt->setString(i + 1, params[i]); // MySQL参数索引从1开始
                }

                sql::ResultSet *res = pstmt->executeQuery();
                nlohmann::json result = ResultSetToJson(res);

                delete res;
                delete pstmt;

                return result;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "MySQL query with params exception: " << e.what();
                LOG_ERROR << "  SQL: " << sql;
                return nlohmann::json::array();
            }
        }

        int MySQLHelper::Execute(const std::string &sql)
        {
            try
            {
                MySQLConnectionGuard guard;
                if (!guard.IsValid())
                {
                    LOG_ERROR << "Failed to get MySQL connection";
                    return -1;
                }

                sql::Statement *stmt = guard->createStatement();
                int affected = stmt->executeUpdate(sql);

                delete stmt;

                LOG_DEBUG << "SQL executed, affected rows: " << affected;
                return affected;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "MySQL execute exception: " << e.what();
                LOG_ERROR << "  SQL: " << sql;
                return -1;
            }
        }

        int MySQLHelper::ExecuteWithParams(const std::string &sql,
                                           const std::vector<std::string> &params)
        {
            try
            {
                MySQLConnectionGuard guard;
                if (!guard.IsValid())
                {
                    LOG_ERROR << "Failed to get MySQL connection";
                    return -1;
                }

                sql::PreparedStatement *pstmt = guard->prepareStatement(sql);

                // 绑定参数
                for (size_t i = 0; i < params.size(); ++i)
                {
                    pstmt->setString(i + 1, params[i]);
                }

                int affected = pstmt->executeUpdate();

                delete pstmt;

                LOG_DEBUG << "SQL executed with params, affected rows: " << affected;
                return affected;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "MySQL execute with params exception: " << e.what();
                LOG_ERROR << "  SQL: " << sql;
                return -1;
            }
        }

        int64_t MySQLHelper::Insert(const std::string &sql)
        {
            try
            {
                MySQLConnectionGuard guard;
                if (!guard.IsValid())
                {
                    LOG_ERROR << "Failed to get MySQL connection";
                    return -1;
                }

                sql::Statement *stmt = guard->createStatement();
                stmt->executeUpdate(sql);

                // 获取最后插入的ID
                sql::ResultSet *res = stmt->executeQuery("SELECT LAST_INSERT_ID()");
                int64_t insert_id = -1;

                if (res->next())
                {
                    insert_id = res->getInt64(1);
                }

                delete res;
                delete stmt;

                LOG_DEBUG << "Insert completed, ID: " << insert_id;
                return insert_id;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "MySQL insert exception: " << e.what();
                LOG_ERROR << "  SQL: " << sql;
                return -1;
            }
        }

        int64_t MySQLHelper::InsertWithParams(const std::string &sql,
                                              const std::vector<std::string> &params)
        {
            try
            {
                MySQLConnectionGuard guard;
                if (!guard.IsValid())
                {
                    LOG_ERROR << "Failed to get MySQL connection";
                    return -1;
                }

                sql::PreparedStatement *pstmt = guard->prepareStatement(sql);

                // 绑定参数
                for (size_t i = 0; i < params.size(); ++i)
                {
                    pstmt->setString(i + 1, params[i]);
                }

                pstmt->executeUpdate();

                // 获取最后插入的ID
                sql::Statement *stmt = guard->createStatement();
                sql::ResultSet *res = stmt->executeQuery("SELECT LAST_INSERT_ID()");

                int64_t insert_id = -1;
                if (res->next())
                {
                    insert_id = res->getInt64(1);
                }

                delete res;
                delete stmt;
                delete pstmt;

                LOG_DEBUG << "Insert with params completed, ID: " << insert_id;
                return insert_id;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "MySQL insert with params exception: " << e.what();
                LOG_ERROR << "  SQL: " << sql;
                return -1;
            }
        }

        /**
         * @brief 开始数据库事务
         *
         * 什么是数据库事务（Transaction）？
         * ------------------------------
         * 事务是一组SQL操作，要么全部成功，要么全部失败（原子性）。
         *
         * ACID特性：
         * - Atomicity（原子性）：事务中的操作要么全部完成，要么全部不完成
         * - Consistency（一致性）：事务前后数据保持一致
         * - Isolation（隔离性）：并发事务之间互不干扰
         * - Durability（持久性）：事务完成后，修改永久保存
         *
         * 为什么需要事务？
         * ----------------
         * 例子：转账操作
         * 1. 从A账户扣款100元
         * 2. 向B账户加款100元
         *
         * 如果没有事务：
         * - 如果步骤1成功，步骤2失败 → A账户扣款了，B账户没收到（钱丢失！）
         *
         * 使用事务：
         * - 两个步骤要么都成功，要么都不执行
         * - 保证数据一致性
         *
         * 使用方式：
         * ----------
         * BeginTransaction(conn);     // 开始事务
         * try {
         *     // 执行多个SQL操作
         *     Execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
         *     Execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
         *     Commit(conn);           // 提交事务（所有操作生效）
         * } catch (...) {
         *     Rollback(conn);         // 回滚事务（撤销所有操作）
         * }
         *
         * @param conn 数据库连接
         * @return 成功返回true
         */
        bool MySQLHelper::BeginTransaction(sql::Connection *conn)
        {
            try
            {
                if (!conn)
                {
                    LOG_ERROR << "Connection is null";
                    return false;
                }

                // 关闭自动提交模式，开始事务
                // 默认情况下MySQL每条SQL语句执行后自动提交
                // setAutoCommit(false)后，需要手动调用commit()才能提交
                conn->setAutoCommit(false);
                LOG_DEBUG << "Transaction started";
                return true;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "Begin transaction exception: " << e.what();
                return false;
            }
        }

        /**
         * @brief 提交事务
         *
         * 作用：使事务中的所有修改永久生效
         *
         * 调用commit()后：
         * - 事务中的所有INSERT、UPDATE、DELETE操作都会写入数据库
         * - 其他数据库连接可以看到这些修改
         * - 修改无法回滚
         *
         * @param conn 数据库连接
         * @return 成功返回true
         */
        bool MySQLHelper::Commit(sql::Connection *conn)
        {
            try
            {
                if (!conn)
                {
                    LOG_ERROR << "Connection is null";
                    return false;
                }

                // 提交事务，使所有修改生效
                conn->commit();
                // 恢复自动提交模式
                conn->setAutoCommit(true);
                LOG_DEBUG << "Transaction committed";
                return true;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "Commit transaction exception: " << e.what();
                return false;
            }
        }

        /**
         * @brief 回滚事务
         *
         * 作用：撤销事务中的所有修改
         *
         * 调用rollback()后：
         * - 事务中的所有INSERT、UPDATE、DELETE操作都被撤销
         * - 数据库恢复到事务开始前的状态
         * - 就像这些操作从未执行过
         *
         * 使用场景：
         * - 发生错误时回滚事务
         * - 业务逻辑验证失败时回滚
         * - 确保数据一致性
         *
         * @param conn 数据库连接
         * @return 成功返回true
         */
        bool MySQLHelper::Rollback(sql::Connection *conn)
        {
            try
            {
                if (!conn)
                {
                    LOG_ERROR << "Connection is null";
                    return false;
                }

                // 回滚事务，撤销所有修改
                conn->rollback();
                // 恢复自动提交模式
                conn->setAutoCommit(true);
                LOG_WARN << "Transaction rolled back";
                return true;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "Rollback transaction exception: " << e.what();
                return false;
            }
        }

        int MySQLHelper::BatchInsert(const std::string &table,
                                     const std::vector<std::string> &fields,
                                     const std::vector<std::vector<std::string>> &values)
        {
            if (values.empty() || fields.empty())
            {
                LOG_WARN << "Batch insert: empty values or fields";
                return 0;
            }

            try
            {
                MySQLConnectionGuard guard;
                if (!guard.IsValid())
                {
                    LOG_ERROR << "Failed to get MySQL connection";
                    return 0;
                }

                // 构建SQL: INSERT INTO table (field1, field2) VALUES (?, ?), (?, ?)...
                std::ostringstream oss;
                oss << "INSERT INTO " << table << " (";

                for (size_t i = 0; i < fields.size(); ++i)
                {
                    if (i > 0)
                        oss << ", ";
                    oss << fields[i];
                }

                oss << ") VALUES ";

                for (size_t i = 0; i < values.size(); ++i)
                {
                    if (i > 0)
                        oss << ", ";
                    oss << "(";
                    for (size_t j = 0; j < fields.size(); ++j)
                    {
                        if (j > 0)
                            oss << ", ";
                        oss << "?";
                    }
                    oss << ")";
                }

                std::string sql = oss.str();
                sql::PreparedStatement *pstmt = guard->prepareStatement(sql);

                // 绑定所有参数
                int param_index = 1;
                for (const auto &row : values)
                {
                    for (const auto &value : row)
                    {
                        pstmt->setString(param_index++, value);
                    }
                }

                int affected = pstmt->executeUpdate();
                delete pstmt;

                LOG_INFO << "Batch insert completed, affected rows: " << affected;
                return affected;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "Batch insert exception: " << e.what();
                return 0;
            }
        }

        nlohmann::json MySQLHelper::ResultSetToJson(sql::ResultSet *res)
        {
            nlohmann::json result = nlohmann::json::array();

            if (!res)
            {
                return result;
            }

            try
            {
                // 获取元数据
                sql::ResultSetMetaData *meta = res->getMetaData();
                int column_count = meta->getColumnCount();

                // 遍历所有行
                while (res->next())
                {
                    nlohmann::json row;

                    for (int i = 1; i <= column_count; ++i)
                    {
                        // 使用getColumnLabel获取别名，如果没有别名则返回列名
                        std::string column_name = meta->getColumnLabel(i);

                        // 根据类型转换
                        int type = meta->getColumnType(i);

                        if (res->isNull(i))
                        {
                            row[column_name] = nullptr;
                        }
                        else if (type == sql::DataType::INTEGER ||
                                 type == sql::DataType::SMALLINT ||
                                 type == sql::DataType::TINYINT)
                        {
                            row[column_name] = res->getInt(i);
                        }
                        else if (type == sql::DataType::BIGINT)
                        {
                            row[column_name] = res->getInt64(i);
                        }
                        else if (type == sql::DataType::REAL ||
                                 type == sql::DataType::DOUBLE ||
                                 type == sql::DataType::DECIMAL)
                        {
                            row[column_name] = res->getDouble(i);
                        }
                        else if (type == sql::DataType::BIT)
                        {
                            row[column_name] = res->getBoolean(i);
                        }
                        else
                        {
                            // 默认作为字符串
                            row[column_name] = res->getString(i);
                        }
                    }

                    result.push_back(row);
                }
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "ResultSet to JSON exception: " << e.what();
            }

            return result;
        }

        // MySQLTransaction实现

        MySQLTransaction::MySQLTransaction(sql::Connection *conn)
            : conn_(conn), committed_(false), rolled_back_(false)
        {

            if (conn_)
            {
                MySQLHelper::BeginTransaction(conn_);
            }
        }

        MySQLTransaction::~MySQLTransaction()
        {
            // 如果既没有提交也没有回滚，自动回滚
            if (conn_ && !committed_ && !rolled_back_)
            {
                LOG_WARN << "Transaction not committed/rolled back, auto rollback";
                Rollback();
            }
        }

        void MySQLTransaction::Commit()
        {
            if (conn_ && !committed_ && !rolled_back_)
            {
                committed_ = MySQLHelper::Commit(conn_);
            }
        }

        void MySQLTransaction::Rollback()
        {
            if (conn_ && !rolled_back_)
            {
                rolled_back_ = MySQLHelper::Rollback(conn_);
            }
        }

    } // namespace database
} // namespace file_server
